MT6589 DRM and Blade panels (v6.16)#33
Closed
akku1139 wants to merge 90 commits into
Closed
Conversation
The mt65xx SoC family uses an earlier version of the SMI, which we refer to as gen 0. Unlike gen 1 or gen 2, gen 0 requires simultaneous access to two distinct MMIO ranges: an AO base for IOMMU configuration and ext base for OSTD, FIFO, and bandwidth limiter setup. Remove the union in struct mtk_smi to allow simultaneous use of smi_ao_base and base. Refactor the probe function into a switch statement to handle the different generation requirements cleanly. Signed-off-by: rva3 <rva333@protonmail.com>
The mt65xx SoC family utilizes a larb design that incorporates features from both gen 1 and gen 2 architectures. Introduce a specific configuration callback for this generation, which implements the port security configuration typical for gen 1 while including the ostd settings found in gen 2. Additionally, add a bandwidth calibration flag for some of the gen 0 SoCs. Signed-off-by: rva3 <rva333@protonmail.com>
The mt65xx SoC family utilizes an earlier version of the IOMMU which shares the same v1 architecture but has minor hardware differences compared to mt2701. Introduce mtk_iommu_type to distinguish between mt2701 and mt65xx variants and apply the necessary logic. Signed-off-by: rva3 <rva333@protonmail.com>
Member
Author
|
maybe needed |
XXX: maybe we should drop this?.. Signed-off-by: rva3 <rva333@protonmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Add a header for the IOMMU ports on the MediaTek MT6589 SoC. Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Add platform data for the SMI common on the MT6589 SoC. Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Make sure to drop the reference taken when looking up the SMI device during common probe on late probe failure (e.g. probe deferral) and on driver unbind. Fixes: 4740475 ("memory: mtk-smi: Add device link for smi-sub-common") Fixes: 038ae37 ("memory: mtk-smi: add missing put_device() call in mtk_smi_device_link_common") Cc: stable@vger.kernel.org # 5.16: 038ae37 Cc: stable@vger.kernel.org # 5.16 Cc: Yong Wu <yong.wu@mediatek.com> Cc: Miaoqian Lin <linmq006@gmail.com> Signed-off-by: Johan Hovold <johan@kernel.org> Link: https://patch.msgid.link/20251121164624.13685-2-johan@kernel.org Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
Make sure to drop the reference taken when looking up the SMI device during larb probe on late probe failure (e.g. probe deferral) and on driver unbind. Fixes: cc8bbe1 ("memory: mediatek: Add SMI driver") Fixes: 038ae37 ("memory: mtk-smi: add missing put_device() call in mtk_smi_device_link_common") Cc: stable@vger.kernel.org # 4.6: 038ae37 Cc: stable@vger.kernel.org # 4.6 Cc: Yong Wu <yong.wu@mediatek.com> Cc: Miaoqian Lin <linmq006@gmail.com> Signed-off-by: Johan Hovold <johan@kernel.org> Link: https://patch.msgid.link/20251121164624.13685-3-johan@kernel.org Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
Clean up device link creation by bailing out early in case the SMI platform device lookup fails. Signed-off-by: Johan Hovold <johan@kernel.org> Link: https://patch.msgid.link/20251121164624.13685-4-johan@kernel.org Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Member
Author
|
TODO: mmsys (done by claude) mutex (done) ovl (done) dsi (done) drm main (done with mt2701_mmsys_driver_data) |
In MT6589, this IP is called "dispsys" for some reason. I don't know more than that. Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
It's in Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml now. Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
everyone will say "fixme" Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Member
Author
|
mmsys routing: |
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Member
Author
Member
Author
|
1369 page: |
Member
Author
|
drop too many ports needs fix |
Member
Author
|
1380: SMI_L1ARB6 |
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Member
Author
|
mt6589 m4u driver will support mt8135 in the future |
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Member
Author
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Member
Author
|
Member
Author
|
smi is ok
|
Member
Author
Member
Author
diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c
index 3e359f6aede0..59645d3ef7c9 100644
--- a/drivers/iommu/mtk_iommu_v1.c
+++ b/drivers/iommu/mtk_iommu_v1.c
@@ -7,6 +7,7 @@
*
* Based on driver/iommu/mtk_iommu.c
*/
+#include <linux/array_size.h>
#include <linux/bug.h>
#include <linux/clk.h>
#include <linux/component.h>
@@ -29,6 +30,7 @@
#include <asm/barrier.h>
#include <dt-bindings/memory/mtk-memory-port.h>
#include <dt-bindings/memory/mt2701-larb-port.h>
+#include <dt-bindings/memory/mt6589-larb-port.h>
#include <soc/mediatek/smi.h>
#if defined(CONFIG_ARM)
@@ -51,6 +53,7 @@ struct dma_iommu_mapping {
#define F_MMU_FAULT_VA_MSK 0xfffff000
#define MTK_PROTECT_PA_ALIGN 128
+/* -------- Common M4U v1 register definitions (MT2701 and MT6589 core) -------- */
#define REG_MMU_CTRL_REG 0x210
#define F_MMU_CTRL_COHERENT_EN BIT(8)
#define REG_MMU_IVRP_PADDR 0x214
@@ -71,6 +74,8 @@ struct dma_iommu_mapping {
#define REG_MMU_FAULT_VA 0x228
#define REG_MMU_INVLD_PA 0x22C
#define REG_MMU_INT_ID 0x388
+
+/* MT2701 specific (core space) */
#define REG_MMU_INVALIDATE 0x5c0
#define REG_MMU_INVLD_START_A 0x5c4
#define REG_MMU_INVLD_END_A 0x5c8
@@ -81,14 +86,80 @@ struct dma_iommu_mapping {
#define REG_MMU_DCM 0x5f0
#define F_MMU_DCM_ON BIT(1)
#define REG_MMU_CPE_DONE 0x60c
+
+/* MT6589 global space registers */
+#define REG_MMUg_CTRL 0x00
+#define F_MMUg_CTRL_INV_EN0 BIT(0)
+#define F_MMUg_CTRL_INV_EN1 BIT(1)
+#define F_MMUg_CTRL_INV_EN2 BIT(2) /* L2 */
+#define F_MMUg_CTRL_PRE_LOCK(en) ((en) ? BIT(3) : 0)
+#define F_MMUg_CTRL_PRE_EN BIT(4)
+
+#define REG_MMUg_INVLD 0x04
+#define F_MMUg_INV_ALL 0x2
+#define F_MMUg_INV_RANGE 0x1
+
+#define REG_MMUg_INVLD_SA 0x08
+#define REG_MMUg_INVLD_EA 0x0C
+#define REG_MMUg_PT_BASE 0x10
+#define F_MMUg_PT_VA_MSK 0xffff0000
+
+#define REG_MMUg_L2_SEL 0x18
+#define F_MMUg_L2_SEL_FLUSH_EN(en) ((en) ? BIT(3) : 0)
+#define F_MMUg_L2_SEL_L2_ULTRA(en) ((en) ? BIT(2) : 0)
+#define F_MMUg_L2_SEL_L2_SHARE(en) ((en) ? BIT(1) : 0)
+#define F_MMUg_L2_SEL_L2_BUS_SEL(go_emi) ((go_emi) ? BIT(0) : 0)
+
+#define REG_MMUg_DCM 0x1C
+#define F_MMUg_DCM_ON(on) ((on) ? BIT(0) : 0)
+
+/* L2 cache registers (MT6589) */
+#define REG_L2_GDC_STATE 0x00
+#define F_L2_GDC_ST_EVENT_MSK GENMASK(7,6)
+#define F_L2_GDC_ST_EVENT_VAL(val) (((val) & 0x3) << 6)
+
+#define REG_L2_GDC_OP 0x04
+#define F_L2_GDC_BYPASS(en) ((en) ? BIT(10) : 0)
+#define F_L2_GDC_PERF_MASK(msk) (((msk) & 0x7) << 7)
+#define GDC_PERF_MASK_HIT_MISS 0
+#define F_L2_GDC_LOCK_ALERT_DIS(dis) ((dis) ? BIT(6) : 0)
+#define F_L2_GDC_PERF_EN(en) ((en) ? BIT(5) : 0)
+#define F_L2_GDC_LOCK_TH(th) (((th) & 0x3) << 2)
+#define F_L2_GDC_PAUSE_OP(op) ((op) & 0x3)
+#define GDC_NO_PAUSE 0
+
+#define REG_L2_GPE_STATUS 0x18
+#define F_L2_GPE_ST_RANGE_INV_DONE BIT(1)
+#define F_L2_GPE_ST_PREFETCH_DONE BIT(0)
+
+/* MT6589 core PFH distance / direction registers */
+#define REG_MMU_PFH_DIST(port) (0x80 + (((port) >> 3) << 2))
+#define F_MMU_PFH_DIST_VAL(port, val) (((val) & 0xf) << (((port) & 0x7) << 2))
+#define F_MMU_PFH_DIST_MASK(port) F_MMU_PFH_DIST_VAL(port, 0xf)
+
+#define REG_MMU_PFH_DIR(port) (((port) < 32) ? 0xF0 : 0xF4)
+#define F_MMU_PFH_DIR(port, val) ((!!(val)) << ((port) & 0x1f))
+
+/* SMI common registers (temporary, to be moved to SMI driver) */
+#define SMI_COMMON_EXT_BASE 0xf0202000
+#define SMI_COMMON_AO_BASE 0xf000E000
+#define REG_SMI_L1LEN 0x200
+#define F_SMI_L1LEN_AXROUTE_G3D_EMI(en) ((en) ? BIT(2) : 0)
+#define F_SMI_L1LEN_AXROUTE_AUDIO_EMI(en) ((en) ? BIT(5) : 0)
+#define REG_SMI_BUS_SEL 0x220
+#define F_SMI_BUS_SEL_larb0(mmu) (((mmu) & 0x3) << 0)
+#define F_SMI_BUS_SEL_larb1(mmu) (((mmu) & 0x3) << 2)
+#define F_SMI_BUS_SEL_larb2(mmu) (((mmu) & 0x3) << 4)
+#define F_SMI_BUS_SEL_larb3(mmu) (((mmu) & 0x3) << 6)
+#define F_SMI_BUS_SEL_larb4(mmu) (((mmu) & 0x3) << 8)
+#define REG_SMI_SECUR_CON(x) (0x05C0 + ((x) << 2))
+
+/* Common page table descriptor bits */
#define F_DESC_VALID 0x2
#define F_DESC_NONSEC BIT(3)
-#define MT2701_M4U_TF_LARB(TF) (6 - (((TF) >> 13) & 0x7))
-#define MT2701_M4U_TF_PORT(TF) (((TF) >> 8) & 0xF)
/* MTK generation one iommu HW only support 4K size mapping */
#define MT2701_IOMMU_PAGE_SHIFT 12
#define MT2701_IOMMU_PAGE_SIZE (1UL << MT2701_IOMMU_PAGE_SHIFT)
-#define MT2701_LARB_NR_MAX 3
/*
* MTK m4u support 4GB iova address space, and only support 4K page
@@ -96,26 +167,74 @@ struct dma_iommu_mapping {
*/
#define M2701_IOMMU_PGT_SIZE SZ_4M
+#define MAX_M4U_CORES 2
+
+struct mtk_iommu_v1_data;
+
+struct mtk_iommu_v1_soc_data {
+ const char *compatible;
+ unsigned int num_cores;
+ bool has_global_base;
+ bool has_l2_cache;
+
+ void (*tlb_flush_all)(struct mtk_iommu_v1_data *data);
+ void (*tlb_flush_range)(struct mtk_iommu_v1_data *data,
+ unsigned long iova, size_t size);
+
+ void (*get_fault_larb_port)(u32 int_id, unsigned int *larb,
+ unsigned int *port);
+
+ int (*hw_init)(struct mtk_iommu_v1_data *data);
+
+ u32 pt_base_reg_offset;
+ bool pt_base_in_global;
+
+ const int *larb_port_offsets;
+ unsigned int num_larb;
+};
+
+struct mtk_iommu_v1_core {
+ void __iomem *base;
+ int irq;
+ struct mtk_iommu_v1_data *data;
+ unsigned int id;
+};
+
struct mtk_iommu_v1_suspend_reg {
+ /* MT2701 fields */
u32 standard_axi_mode;
u32 dcm_dis;
u32 ctrl_reg;
u32 int_control0;
+
+ /* MT6589 additional fields */
+ u32 mmug_ctrl;
+ u32 mmug_pt_base;
+ u32 mmug_l2_sel;
+ u32 mmug_dcm;
+ u32 l2_gdc_op;
+ u32 smi_l1len;
+ u32 smi_bus_sel;
+ u32 smi_secur_con[7];
};
struct mtk_iommu_v1_data {
- void __iomem *base;
- int irq;
- struct device *dev;
- struct clk *bclk;
- phys_addr_t protect_base; /* protect memory base */
- struct mtk_iommu_v1_domain *m4u_dom;
-
- struct iommu_device iommu;
- struct dma_iommu_mapping *mapping;
- struct mtk_smi_larb_iommu larb_imu[MTK_LARB_NR_MAX];
-
- struct mtk_iommu_v1_suspend_reg reg;
+ const struct mtk_iommu_v1_soc_data *soc;
+ struct device *dev;
+
+ struct mtk_iommu_v1_core cores[MAX_M4U_CORES];
+ void __iomem *global_base;
+ void __iomem *l2_base;
+
+ struct clk *bclk;
+ phys_addr_t protect_base;
+ struct mtk_iommu_v1_domain *m4u_dom;
+
+ struct iommu_device iommu;
+ struct dma_iommu_mapping *mapping;
+ struct mtk_smi_larb_iommu larb_imu[MTK_LARB_NR_MAX];
+
+ struct mtk_iommu_v1_suspend_reg reg;
};
struct mtk_iommu_v1_domain {
@@ -150,73 +269,143 @@ static const int mt2701_m4u_in_larb[] = {
MT2701_LARB2_PORT_OFFSET, MT2701_LARB3_PORT_OFFSET
};
-static inline int mt2701_m4u_to_larb(int id)
+static const int mt6589_m4u_in_larb[] = {
+ MT6589_LARB0_PORT_OFFSET, MT6589_LARB1_PORT_OFFSET,
+ MT6589_LARB2_PORT_OFFSET, MT6589_LARB3_PORT_OFFSET,
+ MT6589_LARB4_PORT_OFFSET, MT6589_LARB5_PORT_OFFSET
+};
+
+static inline int mtk_iommu_v1_to_larb(struct mtk_iommu_v1_data *data, int id)
{
+ const int *offsets = data->soc->larb_port_offsets;
+ int num = data->soc->num_larb;
int i;
- for (i = ARRAY_SIZE(mt2701_m4u_in_larb) - 1; i >= 0; i--)
- if ((id) >= mt2701_m4u_in_larb[i])
+ for (i = num - 1; i >= 0; i--)
+ if (id >= offsets[i])
return i;
return 0;
}
-static inline int mt2701_m4u_to_port(int id)
+static inline int mtk_iommu_v1_to_port(struct mtk_iommu_v1_data *data, int id)
{
- int larb = mt2701_m4u_to_larb(id);
+ int larb = mtk_iommu_v1_to_larb(data, id);
+ return id - data->soc->larb_port_offsets[larb];
+}
- return id - mt2701_m4u_in_larb[larb];
+static inline void m4u_set_field(void __iomem *base, u32 reg, u32 mask, u32 val)
+{
+ u32 regval = readl_relaxed(base + reg);
+ regval = (regval & ~mask) | val;
+ writel_relaxed(regval, base + reg);
}
-static void mtk_iommu_v1_tlb_flush_all(struct mtk_iommu_v1_data *data)
+/* MT2701 (single core, no global space) */
+static void mt2701_tlb_flush_all(struct mtk_iommu_v1_data *data)
{
- writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0,
- data->base + REG_MMU_INV_SEL);
- writel_relaxed(F_ALL_INVLD, data->base + REG_MMU_INVALIDATE);
- wmb(); /* Make sure the tlb flush all done */
+ void __iomem *base = data->cores[0].base;
+ writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0, base + REG_MMU_INV_SEL);
+ writel_relaxed(F_ALL_INVLD, base + REG_MMU_INVALIDATE);
+ wmb();
}
-static void mtk_iommu_v1_tlb_flush_range(struct mtk_iommu_v1_data *data,
- unsigned long iova, size_t size)
+static void mt2701_tlb_flush_range(struct mtk_iommu_v1_data *data,
+ unsigned long iova, size_t size)
{
- int ret;
+ void __iomem *base = data->cores[0].base;
u32 tmp;
+ int ret;
- writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0,
- data->base + REG_MMU_INV_SEL);
- writel_relaxed(iova & F_MMU_FAULT_VA_MSK,
- data->base + REG_MMU_INVLD_START_A);
+ writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0, base + REG_MMU_INV_SEL);
+ writel_relaxed(iova & F_MMU_FAULT_VA_MSK, base + REG_MMU_INVLD_START_A);
writel_relaxed((iova + size - 1) & F_MMU_FAULT_VA_MSK,
- data->base + REG_MMU_INVLD_END_A);
- writel_relaxed(F_MMU_INV_RANGE, data->base + REG_MMU_INVALIDATE);
+ base + REG_MMU_INVLD_END_A);
+ writel_relaxed(F_MMU_INV_RANGE, base + REG_MMU_INVALIDATE);
- ret = readl_poll_timeout_atomic(data->base + REG_MMU_CPE_DONE,
- tmp, tmp != 0, 10, 100000);
+ ret = readl_poll_timeout_atomic(base + REG_MMU_CPE_DONE,
+ tmp, tmp != 0, 10, 100000);
if (ret) {
dev_warn(data->dev,
"Partial TLB flush timed out, falling back to full flush\n");
- mtk_iommu_v1_tlb_flush_all(data);
+ mt2701_tlb_flush_all(data);
}
- /* Clear the CPE status */
- writel_relaxed(0, data->base + REG_MMU_CPE_DONE);
+ writel_relaxed(0, base + REG_MMU_CPE_DONE);
+}
+
+/* MT6589 (global control, L2) */
+static void mt6589_tlb_flush_all(struct mtk_iommu_v1_data *data)
+{
+ u32 reg = F_MMUg_CTRL_INV_EN0 | F_MMUg_CTRL_INV_EN1;
+ if (data->l2_base)
+ reg |= F_MMUg_CTRL_INV_EN2;
+
+ writel_relaxed(reg, data->global_base + REG_MMUg_CTRL);
+ writel_relaxed(F_MMUg_INV_ALL, data->global_base + REG_MMUg_INVLD);
+
+ if (data->l2_base) {
+ u32 event;
+ readl_poll_timeout_atomic(data->l2_base + REG_L2_GDC_STATE,
+ event,
+ event & F_L2_GDC_ST_EVENT_MSK,
+ 10, 100000);
+ writel_relaxed(0, data->l2_base + REG_L2_GDC_STATE);
+ }
+}
+
+static void mt6589_tlb_flush_range(struct mtk_iommu_v1_data *data,
+ unsigned long iova, size_t size)
+{
+ u32 reg = F_MMUg_CTRL_INV_EN0 | F_MMUg_CTRL_INV_EN1;
+ if (data->l2_base)
+ reg |= F_MMUg_CTRL_INV_EN2;
+
+ writel_relaxed(reg, data->global_base + REG_MMUg_CTRL);
+ writel_relaxed(iova & F_MMU_FAULT_VA_MSK,
+ data->global_base + REG_MMUg_INVLD_SA);
+ writel_relaxed((iova + size - 1) & F_MMU_FAULT_VA_MSK,
+ data->global_base + REG_MMUg_INVLD_EA);
+ writel_relaxed(F_MMUg_INV_RANGE, data->global_base + REG_MMUg_INVLD);
+
+ if (data->l2_base) {
+ u32 status;
+ readl_poll_timeout_atomic(data->l2_base + REG_L2_GPE_STATUS,
+ status,
+ status & F_L2_GPE_ST_RANGE_INV_DONE,
+ 10, 100000);
+ writel_relaxed(0, data->l2_base + REG_L2_GPE_STATUS);
+ }
+}
+
+static void mt2701_get_fault_larb_port(u32 int_id, unsigned int *larb,
+ unsigned int *port)
+{
+ *larb = 6 - ((int_id >> 13) & 0x7);
+ *port = (int_id >> 8) & 0xF;
+}
+
+static void mt6589_get_fault_larb_port(u32 int_id, unsigned int *larb,
+ unsigned int *port)
+{
+ *larb = (int_id >> 12) & 0x7;
+ *port = (int_id >> 8) & 0xF;
}
static irqreturn_t mtk_iommu_v1_isr(int irq, void *dev_id)
{
- struct mtk_iommu_v1_data *data = dev_id;
+ struct mtk_iommu_v1_core *core = dev_id;
+ struct mtk_iommu_v1_data *data = core->data;
struct mtk_iommu_v1_domain *dom = data->m4u_dom;
u32 int_state, regval, fault_iova, fault_pa;
unsigned int fault_larb, fault_port;
/* Read error information from registers */
- int_state = readl_relaxed(data->base + REG_MMU_FAULT_ST);
- fault_iova = readl_relaxed(data->base + REG_MMU_FAULT_VA);
+ int_state = readl_relaxed(core->base + REG_MMU_FAULT_ST);
+ fault_iova = readl_relaxed(core->base + REG_MMU_FAULT_VA) & F_MMU_FAULT_VA_MSK;
+ fault_pa = readl_relaxed(core->base + REG_MMU_INVLD_PA);
+ regval = readl_relaxed(core->base + REG_MMU_INT_ID);
- fault_iova &= F_MMU_FAULT_VA_MSK;
- fault_pa = readl_relaxed(data->base + REG_MMU_INVLD_PA);
- regval = readl_relaxed(data->base + REG_MMU_INT_ID);
- fault_larb = MT2701_M4U_TF_LARB(regval);
- fault_port = MT2701_M4U_TF_PORT(regval);
+ data->soc->get_fault_larb_port(regval, &fault_larb, &fault_port);
/*
* MTK v1 iommu HW could not determine whether the fault is read or
@@ -225,16 +414,16 @@ static irqreturn_t mtk_iommu_v1_isr(int irq, void *dev_id)
if (report_iommu_fault(&dom->domain, data->dev, fault_iova,
IOMMU_FAULT_READ))
dev_err_ratelimited(data->dev,
- "fault type=0x%x iova=0x%x pa=0x%x larb=%d port=%d\n",
+ "fault type=0x%x iova=0x%x pa=0x%x larb=%d port=%d core=%d\n",
int_state, fault_iova, fault_pa,
- fault_larb, fault_port);
+ fault_larb, fault_port, core->id);
/* Interrupt clear */
- regval = readl_relaxed(data->base + REG_MMU_INT_CONTROL);
+ regval = readl_relaxed(core->base + REG_MMU_INT_CONTROL);
regval |= F_INT_CLR_BIT;
- writel_relaxed(regval, data->base + REG_MMU_INT_CONTROL);
+ writel_relaxed(regval, core->base + REG_MMU_INT_CONTROL);
- mtk_iommu_v1_tlb_flush_all(data);
+ data->soc->tlb_flush_all(data);
return IRQ_HANDLED;
}
@@ -242,14 +431,14 @@ static irqreturn_t mtk_iommu_v1_isr(int irq, void *dev_id)
static void mtk_iommu_v1_config(struct mtk_iommu_v1_data *data,
struct device *dev, bool enable)
{
- struct mtk_smi_larb_iommu *larb_mmu;
- unsigned int larbid, portid;
+ struct mtk_smi_larb_iommu *larb_mmu;
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
- int i;
+ unsigned int larbid, portid, i, mmu_id;
+ void __iomem *base;
for (i = 0; i < fwspec->num_ids; ++i) {
- larbid = mt2701_m4u_to_larb(fwspec->ids[i]);
- portid = mt2701_m4u_to_port(fwspec->ids[i]);
+ larbid = mtk_iommu_v1_to_larb(data, fwspec->ids[i]);
+ portid = mtk_iommu_v1_to_port(data, fwspec->ids[i]);
larb_mmu = &data->larb_imu[larbid];
dev_dbg(dev, "%s iommu port: %d\n",
@@ -260,6 +449,26 @@ static void mtk_iommu_v1_config(struct mtk_iommu_v1_data *data,
else
larb_mmu->mmu &= ~MTK_SMI_MMU_EN(portid);
}
+
+ /* MT6589 specific: set default prefetch distance & direction */
+ if (data->soc->has_global_base) {
+ for (i = 0; i < fwspec->num_ids; i++) {
+ portid = mtk_iommu_v1_to_port(data, fwspec->ids[i]);
+ larbid = mtk_iommu_v1_to_larb(data, fwspec->ids[i]);
+
+ /* Determine which M4U core this LARB is connected to */
+ mmu_id = (larbid == 0 || larbid == 2) ? 0 : 1;
+ base = data->cores[mmu_id].base;
+
+ /* Set distance = 1 */
+ m4u_set_field(base, REG_MMU_PFH_DIST(portid),
+ F_MMU_PFH_DIST_MASK(portid),
+ F_MMU_PFH_DIST_VAL(portid, 1));
+ /* Set direction = 0 */
+ m4u_set_field(base, REG_MMU_PFH_DIR(portid),
+ 1 << (portid & 0x1f), 0);
+ }
+ }
}
static int mtk_iommu_v1_domain_finalise(struct mtk_iommu_v1_data *data)
@@ -273,7 +482,10 @@ static int mtk_iommu_v1_domain_finalise(struct mtk_iommu_v1_data *data)
if (!dom->pgt_va)
return -ENOMEM;
- writel(dom->pgt_pa, data->base + REG_MMU_PT_BASE_ADDR);
+ if (data->soc->pt_base_in_global)
+ writel(dom->pgt_pa, data->global_base + data->soc->pt_base_reg_offset);
+ else
+ writel(dom->pgt_pa, data->cores[0].base + data->soc->pt_base_reg_offset);
dom->data = data;
@@ -365,7 +577,7 @@ static int mtk_iommu_v1_map(struct iommu_domain *domain, unsigned long iova,
spin_unlock_irqrestore(&dom->pgtlock, flags);
*mapped = i * MT2701_IOMMU_PAGE_SIZE;
- mtk_iommu_v1_tlb_flush_range(dom->data, iova, *mapped);
+ dom->data->soc->tlb_flush_range(dom->data, iova, *mapped);
return i == pgcount ? 0 : -EEXIST;
}
@@ -383,7 +595,7 @@ static size_t mtk_iommu_v1_unmap(struct iommu_domain *domain, unsigned long iova
memset(pgt_base_iova, 0, pgcount * sizeof(u32));
spin_unlock_irqrestore(&dom->pgtlock, flags);
- mtk_iommu_v1_tlb_flush_range(dom->data, iova, size);
+ dom->data->soc->tlb_flush_range(dom->data, iova, size);
return size;
}
@@ -433,6 +645,7 @@ static int mtk_iommu_v1_create_mapping(struct device *dev,
return -EINVAL;
dev_iommu_priv_set(dev, platform_get_drvdata(m4updev));
+ put_device(&m4updev->dev);
}
ret = iommu_fwspec_add_ids(dev, args->args, 1);
@@ -482,12 +695,12 @@ static struct iommu_device *mtk_iommu_v1_probe_device(struct device *dev)
data = dev_iommu_priv_get(dev);
/* Link the consumer device with the smi-larb device(supplier) */
- larbid = mt2701_m4u_to_larb(fwspec->ids[0]);
- if (larbid >= MT2701_LARB_NR_MAX)
+ larbid = mtk_iommu_v1_to_larb(data, fwspec->ids[0]);
+ if (larbid >= MTK_LARB_NR_MAX)
return ERR_PTR(-EINVAL);
for (idx = 1; idx < fwspec->num_ids; idx++) {
- larbidx = mt2701_m4u_to_larb(fwspec->ids[idx]);
+ larbidx = mtk_iommu_v1_to_larb(data, fwspec->ids[idx]);
if (larbid != larbidx) {
dev_err(dev, "Can only use one larb. Fail@larb%d-%d.\n",
larbid, larbidx);
@@ -509,14 +722,10 @@ static struct iommu_device *mtk_iommu_v1_probe_device(struct device *dev)
static void mtk_iommu_v1_probe_finalize(struct device *dev)
{
- struct dma_iommu_mapping *mtk_mapping;
- struct mtk_iommu_v1_data *data;
+ struct mtk_iommu_v1_data *data = dev_iommu_priv_get(dev);
int err;
- data = dev_iommu_priv_get(dev);
- mtk_mapping = data->mapping;
-
- err = arm_iommu_attach_device(dev, mtk_mapping);
+ err = arm_iommu_attach_device(dev, data->mapping);
if (err)
dev_err(dev, "Can't create IOMMU mapping - DMA-OPS will not work\n");
}
@@ -524,17 +733,17 @@ static void mtk_iommu_v1_probe_finalize(struct device *dev)
static void mtk_iommu_v1_release_device(struct device *dev)
{
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
- struct mtk_iommu_v1_data *data;
+ struct mtk_iommu_v1_data *data = dev_iommu_priv_get(dev);
struct device *larbdev;
unsigned int larbid;
data = dev_iommu_priv_get(dev);
- larbid = mt2701_m4u_to_larb(fwspec->ids[0]);
+ larbid = mtk_iommu_v1_to_larb(data, fwspec->ids[0]);
larbdev = data->larb_imu[larbid].dev;
device_link_remove(dev, larbdev);
}
-static int mtk_iommu_v1_hw_init(const struct mtk_iommu_v1_data *data)
+static int mt2701_hw_init(struct mtk_iommu_v1_data *data)
{
u32 regval;
int ret;
@@ -546,7 +755,7 @@ static int mtk_iommu_v1_hw_init(const struct mtk_iommu_v1_data *data)
}
regval = F_MMU_CTRL_COHERENT_EN | F_MMU_TF_PROTECT_SEL(2);
- writel_relaxed(regval, data->base + REG_MMU_CTRL_REG);
+ writel_relaxed(regval, data->cores[0].base + REG_MMU_CTRL_REG);
regval = F_INT_TRANSLATION_FAULT |
F_INT_MAIN_MULTI_HIT_FAULT |
@@ -556,23 +765,104 @@ static int mtk_iommu_v1_hw_init(const struct mtk_iommu_v1_data *data)
F_INT_TLB_MISS_FAULT |
F_INT_PFH_DMA_FIFO_OVERFLOW |
F_INT_MISS_DMA_FIFO_OVERFLOW;
- writel_relaxed(regval, data->base + REG_MMU_INT_CONTROL);
+ writel_relaxed(regval, data->cores[0].base + REG_MMU_INT_CONTROL);
- /* protect memory,hw will write here while translation fault */
- writel_relaxed(data->protect_base,
- data->base + REG_MMU_IVRP_PADDR);
+ writel_relaxed(data->protect_base, data->cores[0].base + REG_MMU_IVRP_PADDR);
+ writel_relaxed(F_MMU_DCM_ON, data->cores[0].base + REG_MMU_DCM);
- writel_relaxed(F_MMU_DCM_ON, data->base + REG_MMU_DCM);
+ return 0;
+}
- if (devm_request_irq(data->dev, data->irq, mtk_iommu_v1_isr, 0,
- dev_name(data->dev), (void *)data)) {
- writel_relaxed(0, data->base + REG_MMU_PT_BASE_ADDR);
- clk_disable_unprepare(data->bclk);
- dev_err(data->dev, "Failed @ IRQ-%d Request\n", data->irq);
- return -ENODEV;
+static int mt6589_hw_init(struct mtk_iommu_v1_data *data)
+{
+ u32 regval;
+ int i, ret;
+ void __iomem *smi_ext, *smi_ao;
+
+ /* Map SMI common regions temporarily (should be done by SMI driver) */
+ smi_ext = ioremap(SMI_COMMON_EXT_BASE, 0x500);
+ smi_ao = ioremap(SMI_COMMON_AO_BASE, 0x1000);
+ if (!smi_ext || !smi_ao) {
+ dev_err(data->dev, "Failed to map SMI common registers\n");
+ ret = -ENOMEM;
+ goto err_iomap;
+ }
+
+ ret = clk_prepare_enable(data->bclk);
+ if (ret) {
+ dev_err(data->dev, "Failed to enable bclk\n");
+ goto err_clk;
+ }
+
+ /* ---- SMI routing (LARB to M4U core) ---- */
+ /* LARB 0 -> M4U0, 1 -> M4U1, 2 -> M4U0, 3 -> M4U1, 4 -> M4U1 */
+ regval = F_SMI_BUS_SEL_larb0(0) | F_SMI_BUS_SEL_larb1(1) |
+ F_SMI_BUS_SEL_larb2(0) | F_SMI_BUS_SEL_larb3(1) |
+ F_SMI_BUS_SEL_larb4(1);
+ writel_relaxed(regval, smi_ext + REG_SMI_BUS_SEL);
+
+ /* Default security: non-secure, domain=3, physical */
+ for (i = 0; i < 7; i++)
+ writel_relaxed(0x66666666, smi_ao + REG_SMI_SECUR_CON(i));
+
+ /* Route G3D and AUDIO to EMI */
+ m4u_set_field(smi_ext, REG_SMI_L1LEN,
+ F_SMI_L1LEN_AXROUTE_G3D_EMI(1),
+ F_SMI_L1LEN_AXROUTE_G3D_EMI(1));
+ m4u_set_field(smi_ext, REG_SMI_L1LEN,
+ F_SMI_L1LEN_AXROUTE_AUDIO_EMI(1),
+ F_SMI_L1LEN_AXROUTE_AUDIO_EMI(1));
+
+ /* ---- Global registers ---- */
+ writel_relaxed(F_MMUg_L2_SEL_FLUSH_EN(1) | F_MMUg_L2_SEL_L2_ULTRA(1) |
+ F_MMUg_L2_SEL_L2_SHARE(0) | F_MMUg_L2_SEL_L2_BUS_SEL(1),
+ data->global_base + REG_MMUg_L2_SEL);
+ writel_relaxed(F_MMUg_DCM_ON(1), data->global_base + REG_MMUg_DCM);
+
+ /* ---- L2 cache ---- */
+ if (data->l2_base) {
+ regval = F_L2_GDC_BYPASS(0) |
+ F_L2_GDC_PERF_MASK(GDC_PERF_MASK_HIT_MISS) |
+ F_L2_GDC_LOCK_ALERT_DIS(0) |
+ F_L2_GDC_LOCK_TH(3) |
+ F_L2_GDC_PAUSE_OP(GDC_NO_PAUSE);
+ writel_relaxed(regval, data->l2_base + REG_L2_GDC_OP);
}
+ /* ---- Per-core setup ---- */
+ for (i = 0; i < data->soc->num_cores; i++) {
+ void __iomem *base = data->cores[i].base;
+
+ regval = 0; /* PFH enabled, walk enabled, cohere disabled */
+ regval |= F_MMU_TF_PROTECT_SEL(2);
+ writel_relaxed(regval, base + REG_MMU_CTRL_REG);
+
+ regval = F_INT_TRANSLATION_FAULT |
+ F_INT_MAIN_MULTI_HIT_FAULT |
+ F_INT_INVALID_PA_FAULT |
+ F_INT_ENTRY_REPLACEMENT_FAULT |
+ F_INT_TABLE_WALK_FAULT |
+ F_INT_TLB_MISS_FAULT |
+ F_INT_PFH_DMA_FIFO_OVERFLOW |
+ F_INT_MISS_DMA_FIFO_OVERFLOW;
+ writel_relaxed(regval, base + REG_MMU_INT_CONTROL);
+
+ writel_relaxed(data->protect_base, base + REG_MMU_IVRP_PADDR);
+ }
+
+ /* Release temporary mappings */
+ iounmap(smi_ext);
+ iounmap(smi_ao);
+
return 0;
+
+err_clk:
+ iounmap(smi_ext);
+ iounmap(smi_ao);
+err_iomap:
+ if (smi_ext) iounmap(smi_ext);
+ if (smi_ao) iounmap(smi_ao);
+ return ret;
}
static const struct iommu_ops mtk_iommu_v1_ops = {
@@ -593,8 +883,39 @@ static const struct iommu_ops mtk_iommu_v1_ops = {
}
};
+static const struct mtk_iommu_v1_soc_data mt2701_soc_data = {
+ .compatible = "mediatek,mt2701-m4u",
+ .num_cores = 1,
+ .has_global_base = false,
+ .has_l2_cache = false,
+ .tlb_flush_all = mt2701_tlb_flush_all,
+ .tlb_flush_range = mt2701_tlb_flush_range,
+ .get_fault_larb_port = mt2701_get_fault_larb_port,
+ .hw_init = mt2701_hw_init,
+ .pt_base_reg_offset = REG_MMU_PT_BASE_ADDR,
+ .pt_base_in_global = false,
+ .larb_port_offsets = mt2701_m4u_in_larb,
+ .num_larb = ARRAY_SIZE(mt2701_m4u_in_larb),
+};
+
+static const struct mtk_iommu_v1_soc_data mt6589_soc_data = {
+ .compatible = "mediatek,mt6589-m4u",
+ .num_cores = 2,
+ .has_global_base = true,
+ .has_l2_cache = true,
+ .tlb_flush_all = mt6589_tlb_flush_all,
+ .tlb_flush_range = mt6589_tlb_flush_range,
+ .get_fault_larb_port = mt6589_get_fault_larb_port,
+ .hw_init = mt6589_hw_init,
+ .pt_base_reg_offset = REG_MMUg_PT_BASE,
+ .pt_base_in_global = true,
+ .larb_port_offsets = mt6589_m4u_in_larb,
+ .num_larb = ARRAY_SIZE(mt6589_m4u_in_larb),
+};
+
static const struct of_device_id mtk_iommu_v1_of_ids[] = {
- { .compatible = "mediatek,mt2701-m4u", },
+ { .compatible = "mediatek,mt2701-m4u", .data = &mt2701_soc_data },
+ { .compatible = "mediatek,mt6589-m4u", .data = &mt6589_soc_data },
{}
};
MODULE_DEVICE_TABLE(of, mtk_iommu_v1_of_ids);
@@ -606,52 +927,103 @@ static const struct component_master_ops mtk_iommu_v1_com_ops = {
static int mtk_iommu_v1_probe(struct platform_device *pdev)
{
- struct device *dev = &pdev->dev;
- struct mtk_iommu_v1_data *data;
- struct resource *res;
- struct component_match *match = NULL;
- void *protect;
- int larb_nr, ret, i;
+ struct device *dev = &pdev->dev;
+ struct mtk_iommu_v1_data *data;
+ const struct mtk_iommu_v1_soc_data *soc;
+ struct component_match *match = NULL;
+ void *protect;
+ int i, larb_nr, ret;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->dev = dev;
+ soc = of_device_get_match_data(dev);
+ data->soc = soc;
- /* Protect memory. HW will access here while translation fault.*/
+ /* Protect memory (HW writes here on translation fault) */
protect = devm_kcalloc(dev, 2, MTK_PROTECT_PA_ALIGN,
GFP_KERNEL | GFP_DMA);
if (!protect)
return -ENOMEM;
data->protect_base = ALIGN(virt_to_phys(protect), MTK_PROTECT_PA_ALIGN);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- data->base = devm_ioremap_resource(dev, res);
- if (IS_ERR(data->base))
- return PTR_ERR(data->base);
-
- data->irq = platform_get_irq(pdev, 0);
- if (data->irq < 0)
- return data->irq;
+ /* Map register bases */
+ if (soc->has_global_base) {
+ data->global_base = devm_platform_ioremap_resource_byname(pdev,
+ "global");
+ if (IS_ERR(data->global_base))
+ return PTR_ERR(data->global_base);
+ }
+ for (i = 0; i < soc->num_cores; i++) {
+ char name[8];
+ snprintf(name, sizeof(name), "m4u%d", i);
+ data->cores[i].base = devm_platform_ioremap_resource_byname(pdev,
+ name);
+ if (IS_ERR(data->cores[i].base))
+ return PTR_ERR(data->cores[i].base);
+ data->cores[i].data = data;
+ data->cores[i].id = i;
+ }
+ if (soc->has_l2_cache) {
+ data->l2_base = devm_platform_ioremap_resource_byname(pdev,
+ "l2cache");
+ if (IS_ERR(data->l2_base))
+ return PTR_ERR(data->l2_base);
+ }
+ /* Clock */
data->bclk = devm_clk_get(dev, "bclk");
if (IS_ERR(data->bclk))
return PTR_ERR(data->bclk);
+ /* Interrupts - request after hw_init to avoid spurious IRQs? but
+ we need the core IRQs ready before registering ISR. We'll request
+ them after hw_init for simplicity. */
+ ret = soc->hw_init(data);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < soc->num_cores; i++) {
+ struct mtk_iommu_v1_core *core = &data->cores[i];
+ char irqname[8];
+ snprintf(irqname, sizeof(irqname), "m4u%d", i);
+ core->irq = platform_get_irq_byname(pdev, irqname);
+ if (core->irq < 0) {
+ ret = core->irq;
+ goto err_clk;
+ }
+ ret = devm_request_irq(dev, core->irq, mtk_iommu_v1_isr, 0,
+ dev_name(dev), core);
+ if (ret) {
+ dev_err(dev, "Failed to request IRQ %d for core%d\n",
+ core->irq, i);
+ goto err_clk;
+ }
+ }
+
+ /* LARB links */
larb_nr = of_count_phandle_with_args(dev->of_node,
"mediatek,larbs", NULL);
- if (larb_nr < 0)
- return larb_nr;
+ if (larb_nr < 0) {
+ ret = larb_nr;
+ goto err_clk;
+ }
+ if (larb_nr > MTK_LARB_NR_MAX) {
+ ret = -EINVAL;
+ goto err_clk;
+ }
for (i = 0; i < larb_nr; i++) {
struct device_node *larbnode;
struct platform_device *plarbdev;
larbnode = of_parse_phandle(dev->of_node, "mediatek,larbs", i);
- if (!larbnode)
- return -EINVAL;
-
+ if (!larbnode) {
+ ret = -EINVAL;
+ goto out_put_larbs;
+ }
if (!of_device_is_available(larbnode)) {
of_node_put(larbnode);
continue;
@@ -660,11 +1032,14 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
plarbdev = of_find_device_by_node(larbnode);
if (!plarbdev) {
of_node_put(larbnode);
- return -ENODEV;
+ ret = -ENODEV;
+ goto out_put_larbs;
}
if (!plarbdev->dev.driver) {
of_node_put(larbnode);
- return -EPROBE_DEFER;
+ put_device(&plarbdev->dev);
+ ret = -EPROBE_DEFER;
+ goto out_put_larbs;
}
data->larb_imu[i].dev = &plarbdev->dev;
@@ -674,29 +1049,29 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
- ret = mtk_iommu_v1_hw_init(data);
+ ret = iommu_device_sysfs_add(&data->iommu, dev, NULL,
+ dev_name(dev));
if (ret)
- return ret;
-
- ret = iommu_device_sysfs_add(&data->iommu, &pdev->dev, NULL,
- dev_name(&pdev->dev));
- if (ret)
- goto out_clk_unprepare;
+ goto out_put_larbs;
ret = iommu_device_register(&data->iommu, &mtk_iommu_v1_ops, dev);
if (ret)
goto out_sysfs_remove;
- ret = component_master_add_with_match(dev, &mtk_iommu_v1_com_ops, match);
+ ret = component_master_add_with_match(dev, &mtk_iommu_v1_com_ops,
+ match);
if (ret)
goto out_dev_unreg;
- return ret;
+ return 0;
out_dev_unreg:
iommu_device_unregister(&data->iommu);
out_sysfs_remove:
iommu_device_sysfs_remove(&data->iommu);
-out_clk_unprepare:
+out_put_larbs:
+ for (i = 0; i < MTK_LARB_NR_MAX; i++)
+ put_device(data->larb_imu[i].dev);
+err_clk:
clk_disable_unprepare(data->bclk);
return ret;
}
@@ -704,26 +1079,56 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
static void mtk_iommu_v1_remove(struct platform_device *pdev)
{
struct mtk_iommu_v1_data *data = platform_get_drvdata(pdev);
+ int i;
iommu_device_sysfs_remove(&data->iommu);
iommu_device_unregister(&data->iommu);
clk_disable_unprepare(data->bclk);
- devm_free_irq(&pdev->dev, data->irq, data);
+ for (i = 0; i < data->soc->num_cores; i++)
+ devm_free_irq(&pdev->dev, data->cores[i].irq, &data->cores[i]);
component_master_del(&pdev->dev, &mtk_iommu_v1_com_ops);
+
+ for (i = 0; i < MTK_LARB_NR_MAX; i++)
+ put_device(data->larb_imu[i].dev);
}
static int __maybe_unused mtk_iommu_v1_suspend(struct device *dev)
{
struct mtk_iommu_v1_data *data = dev_get_drvdata(dev);
struct mtk_iommu_v1_suspend_reg *reg = &data->reg;
- void __iomem *base = data->base;
+ void __iomem *base = data->cores[0].base;
- reg->standard_axi_mode = readl_relaxed(base +
- REG_MMU_STANDARD_AXI_MODE);
- reg->dcm_dis = readl_relaxed(base + REG_MMU_DCM);
+ /* Common core registers */
reg->ctrl_reg = readl_relaxed(base + REG_MMU_CTRL_REG);
reg->int_control0 = readl_relaxed(base + REG_MMU_INT_CONTROL);
+
+ if (data->soc->has_global_base) {
+ reg->mmug_ctrl = readl_relaxed(data->global_base + REG_MMUg_CTRL);
+ reg->mmug_pt_base = readl_relaxed(data->global_base + REG_MMUg_PT_BASE);
+ reg->mmug_l2_sel = readl_relaxed(data->global_base + REG_MMUg_L2_SEL);
+ reg->mmug_dcm = readl_relaxed(data->global_base + REG_MMUg_DCM);
+ if (data->l2_base)
+ reg->l2_gdc_op = readl_relaxed(data->l2_base + REG_L2_GDC_OP);
+
+ /* Save SMI registers (temporary) */
+ void __iomem *smi_ext = ioremap(SMI_COMMON_EXT_BASE, 0x500);
+ void __iomem *smi_ao = ioremap(SMI_COMMON_AO_BASE, 0x1000);
+ if (smi_ext && smi_ao) {
+ reg->smi_l1len = readl_relaxed(smi_ext + REG_SMI_L1LEN);
+ reg->smi_bus_sel = readl_relaxed(smi_ext + REG_SMI_BUS_SEL);
+ for (int i = 0; i < 7; i++)
+ reg->smi_secur_con[i] = readl_relaxed(smi_ao + REG_SMI_SECUR_CON(i));
+ }
+ iounmap(smi_ext);
+ iounmap(smi_ao);
+ } else {
+ /* MT2701 specific */
+ base = data->cores[0].base;
+ reg->standard_axi_mode = readl_relaxed(base + REG_MMU_STANDARD_AXI_MODE);
+ reg->dcm_dis = readl_relaxed(base + REG_MMU_DCM);
+ }
+
return 0;
}
@@ -731,15 +1136,51 @@ static int __maybe_unused mtk_iommu_v1_resume(struct device *dev)
{
struct mtk_iommu_v1_data *data = dev_get_drvdata(dev);
struct mtk_iommu_v1_suspend_reg *reg = &data->reg;
- void __iomem *base = data->base;
-
- writel_relaxed(data->m4u_dom->pgt_pa, base + REG_MMU_PT_BASE_ADDR);
- writel_relaxed(reg->standard_axi_mode,
- base + REG_MMU_STANDARD_AXI_MODE);
- writel_relaxed(reg->dcm_dis, base + REG_MMU_DCM);
- writel_relaxed(reg->ctrl_reg, base + REG_MMU_CTRL_REG);
- writel_relaxed(reg->int_control0, base + REG_MMU_INT_CONTROL);
- writel_relaxed(data->protect_base, base + REG_MMU_IVRP_PADDR);
+ void __iomem *base = data->cores[0].base;
+
+ if (data->soc->has_global_base) {
+ writel_relaxed(reg->mmug_ctrl, data->global_base + REG_MMUg_CTRL);
+ writel_relaxed(reg->mmug_pt_base, data->global_base + REG_MMUg_PT_BASE);
+ writel_relaxed(reg->mmug_l2_sel, data->global_base + REG_MMUg_L2_SEL);
+ writel_relaxed(reg->mmug_dcm, data->global_base + REG_MMUg_DCM);
+ if (data->l2_base)
+ writel_relaxed(reg->l2_gdc_op, data->l2_base + REG_L2_GDC_OP);
+
+ /* Restore SMI registers */
+ void __iomem *smi_ext = ioremap(SMI_COMMON_EXT_BASE, 0x500);
+ void __iomem *smi_ao = ioremap(SMI_COMMON_AO_BASE, 0x1000);
+ if (smi_ext && smi_ao) {
+ writel_relaxed(reg->smi_l1len, smi_ext + REG_SMI_L1LEN);
+ writel_relaxed(reg->smi_bus_sel, smi_ext + REG_SMI_BUS_SEL);
+ for (int i = 0; i < 7; i++)
+ writel_relaxed(reg->smi_secur_con[i], smi_ao + REG_SMI_SECUR_CON(i));
+ }
+ iounmap(smi_ext);
+ iounmap(smi_ao);
+ }
+
+ /* Per-core restore (common) */
+ for (int i = 0; i < data->soc->num_cores; i++) {
+ base = data->cores[i].base;
+ writel_relaxed(reg->ctrl_reg, base + REG_MMU_CTRL_REG);
+ writel_relaxed(reg->int_control0, base + REG_MMU_INT_CONTROL);
+ writel_relaxed(data->protect_base, base + REG_MMU_IVRP_PADDR);
+ }
+
+ if (!data->soc->has_global_base) {
+ /* MT2701 extra */
+ base = data->cores[0].base;
+ writel_relaxed(reg->standard_axi_mode, base + REG_MMU_STANDARD_AXI_MODE);
+ writel_relaxed(reg->dcm_dis, base + REG_MMU_DCM);
+ }
+
+ if (data->m4u_dom && data->m4u_dom->pgt_pa) {
+ if (data->soc->pt_base_in_global)
+ writel_relaxed(data->m4u_dom->pgt_pa, data->global_base + data->soc->pt_base_reg_offset);
+ else
+ writel_relaxed(data->m4u_dom->pgt_pa, data->cores[0].base + data->soc->pt_base_reg_offset);
+ }
+
return 0;
}
wip deepseek https://chat.deepseek.com/a/chat/s/57f1d733-d562-41af-a8b4-8e6da9896b80 |
Member
Author
|
do not merge into blade/6.16 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
thanks to rva3
https://github.com/mt6572-mainline/linux